perm filename SUPSER.MID[NET,MRC]2 blob sn#339547 filedate 1978-03-05 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00017 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00003 00002	TITLE SUPSER
C00005 00003	ITS TTY definitions
C00009 00004	ITS output buffer codes
C00011 00005	Data area
C00014 00006	Interrupt server
C00016 00007	Start of program
C00018 00008	Log this connection
C00020 00009	Paw over user console characteristics
C00022 00010	Final initialization
C00024 00011	Network input interrupt
C00026 00012	 Send character to the PTY
C00029 00013	PTY input interrupt
C00032 00014	 Datamedia conversion subroutines
C00035 00015	Datamedia command table
C00038 00016	 More DM command frobs
C00041 00017	Subroutines
C00044 ENDMK
C⊗;
TITLE SUPSER
SUBTTL Definitions

; Mark Crispin, SU-AI, March 1978

; Assembly switches

IFNDEF SVRSKT,SVRSKT==137		; default listen socket
IFNDEF LOKTMO,LOKTMO==5			; # of 15-second frobs of lock timeout
IFNDEF PDLLEN,PDLLEN==50		; stack length
IFNDEF VSZMAX,VSZMAX==50.		; maximum TCMXV

; AC definitions.  0→3 are used by NETWRK

X=4 ? Y=5 ? Z=6 ? A=7 ? B=10 ? C=11 ? P=17

; SAIL system bit definitions

INTPTO==001000,,			; PTY interrupt
INTCLK==000200,,			; clock interrupt
DMLIN== 040000,,			; Datamedia
IMPBIT==001000,,			; IMP TTY
FCS==   000020,,			; full character set mode
FULTWX==000004,,			; no echo
TLKRNG==000001,,			; TALKing
SUBTTL ITS TTY definitions

;  These definitions are the various bits, words, etc. for the ITS terminal
; service system calls and are here for convenience and clarity.  This is
; abridged from [MIT-AI] SYSTEM;BITS >, the monitor bits definition file.

; TTYOPT variable (terminal capabilities)

%TOALT==200000,,			; 1 → standardise altmodes
%TOCLC==100000,,			; 1 → convert cases on input
%TOERS==040000,,			; 1 → this terminal can erase
%TOHDX==020000,,			; 1 → half duplex
%TOMVB==010000,,			; 1 → can backspace
%TOSAI==004000,,			; 1 → has SAIL graphics
%TOSA1==002000,,			; 1 → init %TSSAI in new jobs (use graphics)
%TOOVR==001000,,			; 1 → can overprint
%TOMVU==000400,,			; 1 → can line starve (ie a display)
%TOMOR==000200,,			; 1 → do **More** processing (init %TSMOR)
%TOROL==000100,,			; 1 → scroll (init %TSROL for new jobs)
%TORAW==000040,,			; 1 → no cursor motion optimization
%TOLWR==000020,,			; 1 → lower case keyboard
%TOFCI==000010,,			; 1 → has bucky bit keyboard
%TOIML==000004,,			; 1 → acts like a grIMLAC (funny ↑PF, ↑PB)
%TOLID==000002,,			; 1 → can insert/delete lines
%TOCID==000001,,			; 1 → can insert/delete characters
%TPPLF==700000				; LF padding
%TPPCR==070000				; CR padding
%TPPTB==007000				; TAB padding (0 → no tabs, 1 → tabs)
%TPTEL==000100				; 1 → CR → CRLF for ARPAnet protocol
%TPCBS==000040				; 1 → intelligent terminal protocol (↑\)
%TP11T==000020				; 1 → PDP-11 TV (reflects %TY11T)
%TPORS==000010				; 1 → output reset should do something
%TPIBC==000002				; 1 → correspondence code 2741
%TPIBM==000001				; 1 → IBM 2741

; TCTYP variable (terminal type)

%TNPRT==0				; printing console, glass TTY, etc.
%TNDP==1				; good Datapoint
%TNODP==2				; inferior losing Datapoint
%TNIML==3				; grIMLAC
%TNTEK==4				; Tektronix 4000 series
%TNTV==5				; PDP-11 TV
%TNMEM==6				; Memowreck
%TNSFW==7				; Software
%TNTRM==10				; Terminet
%TNESC==11				; ASCII standard display (VT52, etc.)
%TNDTM==12				; Datamedia 2500
%TNMAX==13				; 1 + largest terminal type

; Components of an input character in 12-bit mode.

%TXASC==0177				; ASCII part
%TXCTL==0200				; control
%TXMTA==0400				; meta
%TXSFT==1000				; shift
%TXSFL==2000				; shift lock
%TXTOP==4000				; top
subttl ITS output buffer codes

; These are the ITS output buffer codes (used by Software terminals).

%TDMOV==200				; move cursor OV OH NV NH
%TDMV1==201				; move cursor; NV NH
%TDEOF==202				; clear to end of screen
%TDEOL==203				; clear to end of line
%TDDLF==204				; delete character after cursor
%TDMTF==205				; motor off
%TDMTN==206				; motor on
%TDCRL==207				; terpri
%TDNOP==210				; no-op
%TDBS==211				; backspace
%TDLF==212				; line feed
%TDRCR==213				; carriage return
%TDORS==214				; output reset
%TDQOT==215				; quote next character (mystery command)
%TDFS==216				; cursor forward
%TDMV0==217				; move cursor NV NH
%TDCLR==220				; clear screen
%TDBEL==221				; feep!
%TDINI==222				; reset reset reset
%TDILP==223				; insert line; count
%TDDLP==224				; delete line; count
%TDICP==225				; insert character; count
%TDDCP==226				; delete character; count
%TDBOW==227				; inverse video
%TDRST==230				; reset inverse video, etc.
%TDMAX==231				; 1 + largest display code
SUBTTL Data area

; TTYSET command words

TYSBLK==.
SETVSZ:	016400,,0			; set screen height
GAGOFF:	024400,,0			; gag off
MODSET:	014400,,0			; set DM mode
NTYSTS==.-TYSBLK

; Terminal location string

TERMID:	'TERMID

CORBEG==.				; start of initialized core storage

TERSTR:	BLOCK 10.			; console location string

; Terminal characteristics

CNSBLK:	BLOCK 1				; CNSGET info
TCTYP:	BLOCK 1				; TCTYP for server
TTYOPT:	BLOCK 1				; TTYOPT for server
TCMXV:	BLOCK 1				; TTY page length
TCMXH:	BLOCK 1				; TTY width
TTYROL:	BLOCK 1				; TTYROL variable
CNSBLL==.-CNSBLK

; Datamedia translator variables

HPOS:	BLOCK 1				; horizontal position
VPOS:	BLOCK 1				; vertical position
SCRMST:	BLOCK 3*<VSZMAX+1>		; screen character allocation table
GETCXP:	BLOCK 1				; -1 → get cursor X position
GETCYP:	BLOCK 1				; -1 → get cursor Y position
INDLMP:	BLOCK 1				; -1 → in I/D mode
ROLLP:	BLOCK 1				; -1 → in roll mode
LFFLSP:	BLOCK 1				; -1 → flush a line feed
QUOTEP:	BLOCK 1				; -1 → quote next character
128CHP:	BLOCK 1				; -1 → FCS terminal
OVRPRP:	BLOCK 1				; -1 → TV terminal

; Interrupt flags

PTINTP:	BLOCK 1				; -1 → PTI interrupt
NTINTP:	BLOCK 1				; -1 → NTI interrupt

; Protocol flags

PRESCP:	BLOCK 1				; -1 → protocol escape seen
SDCMDP:	BLOCK 1				; -1 → in SUPDUP protocol command
EATERP:	BLOCK 1				; -1 → getting terminal string
NODETP:	BLOCK 1				; -1 → don't detach this guy
BKYBTS:	BLOCK 1				; -1 → incoming bucky bits

; Other storage

TERMBP:	BLOCK 1				; terminal byte pointer
TTYLIN:	BLOCK 1				; line number of PTY
IDLTIM:	BLOCK 1				; idle time in 15-second units
PDL:	BLOCK PDLLEN			; stack

COREND==.-1				; end of initialized storage
SUBTTL Interrupt server

;  Interrupts only set flags which the main program (normally in INTW⊗
; state) looks at.

INTSER:	SKIPN X,JOBCNI			; get interrupt status
	 JRST 4,.-1
	TLNE X,(INTPTO)			; PTY int
	 SETOM PTINTP
	TLNE X,(INTCLK)			; CLK int
	 JRST CLKSER
	TLNE X,(INTINP)			; NTI int
	 SETOM NTINTP
	TLNE X,(INTIMS)			; status change
	 JRST INTDIE
	TLNE X,(INTINR)
	 OUTSTR [ASCIZ/*INR*
/]
	TLNE X,(INTINS)			; IMP INS int
	 OUTSTR [ASCIZ/*INS*
/]
	DISMIS

; Service clock interrupt

CLKSER:	AOSE IDLTIM			; bump idle time
	 JRST CLKSR1
	UNLOCK				; idle timeout; unlock
	MOVE TTYLIN
	PTGETL
	TLNE 1,(TLKRNG)			; TALKing?
	 JRST CLKSR1			; don't kill him if so!
	TTYJOB
	JUMPN CLKSR1
	SETOM NODETP			; forget about detaching
	JRST INTDIE			; idle and not logged in--bye bye!
CLKSR1:	MOVEI 2				; check connection status
	MTAPE NET,
	TLNN 1,(CLSS\CLSR)		; send side gronked?
	 TLNE 2,(CLSS\CLSR)		; receive side?
	  JRST INTDIE
	DISMIS
SUBTTL Start of program

SUPSER:	JFCL
	RESET
	MOVE ['SUPSER]
	SETNAM
	SETZM CORBEG
	MOVE [CORBEG,,CORBEG+1]
	BLT COREND
	MOVE P,[PDL(-PDLLEN)]
	MOVEI [DEBREAK ? EXIT]
	MOVEM JOBAPR
	CLKINT 5.*60.*60.		; must die if around too long
	OUTSTR [ASCIZ/SUPSER started
/]

; Listen for a connection on our socket

	SETOM NODETP			; don't try to detach
	MOVEI SVRSKT
	MOVEM LSNSKT
	PUSHJ P,LISTEN

; Set up interrupts

	MOVEI INTSER
	MOVEM JOBAPR			; set up server location
	CLKINT 60.*15.			; start slow ticking clock
	MOVSI (INTPTO\INTCLK\INTINR\INTINS\INTIMS\INTINP)
	INTENB				; turn on interrupts

; Set up terminal id for interested spies

	MOVEI TERMID
	MOVEM JOBVER
SUBTTL Log this connection

	OUTSTR [ASCIZ/Connected to /]
	PUSHJ P,MAPHST			; map in host table
	MOVE HOST
	PUSHJ P,HSTNUM			; get HDB
	 JFCL				; sorry about errors
	MOVEI Y,(1)			; host name
	HRLI Y,440700
	SKIPA X,[440700,,TERSTR]
CPYHST:	 IDPB Z,X
	ILDB Z,Y
	JUMPN Z,CPYHST
	HLRZ Y,1			; pointer to system name
	MOVE Z,(Y)			; get system name
	MOVE Y,FSOCKT			; and ICP socket
	CAMN Z,[ASCII/TIP/]		; on a TIP?  (with SUPDUP???)
	 TRNE Y,177774			; just paranoia; make sure a TIP port
	  JRST NOTTIP
	MOVEI Z,"#
	IDPB Z,X
	LSH Y,-16.
	IDIVI Y,8.			; ports are octal
	JUMPE Y,1DIGTP
	ADDI Y,"0 ? IDPB Y,X
1DIGTP:	ADDI Z,"0 ? IDPB Z,X
NOTTIP:	MOVEM X,TERMBP
	PUSHJ P,SETANM			; set our alias name
	PUSHJ P,UNMHST			; map out the host table
	OUTSTR TERSTR
	OUTSTR [ASCIZ/
/]
SUBTTL Paw over user console characteristics

; Get terminal characteristics

	MOVE Y,[440600,,CNSBLK]		; pointer to characteristics block
	MOVEI Z,6
GETSIZ:	PUSHJ P,NETICW
	IDPB Y
	SOJG Z,GETSIZ
	HLRO X,CNSBLK
	MOVNS Z,X			; size of block
	CAILE Z,CNSBLL-1
	 MOVEI Z,CNSBLL-1		; additional args we don't know about
	IMULI Z,6
GETCNS:	PUSHJ P,NETICW
	IDPB Y
	SOJG Z,GETCNS
	CAIN X,CNSBLL-1
	 JRST CHKTRM
	CAIG X,CNSBLL			; more than we wanted?
	 JRST [	OUTSTR [ASCIZ/User sent too few args!
/]
		JRST CHKTRM]
	OUTSTR [ASCIZ/User sent too many args!
/]
	SUBI X,CNSBLL-1
	IMULI X,6
	PUSHJ P,NETICW			; eat extra bytes
	SOJG X,.-1

; Check terminal out

CHKTRM:	MOVE TCTYP
	CAIE %TNSFW			; software?
	 JRST [	MOVEI X,[ASCIZ/Invalid TCTYP setting!
/]
		OUTSTR (X)
		PUSHJ P,SNDMSG
		JRST SUICID]
	MOVE TTYOPT
	TLNE (%TOOVR)
	 SETOM OVRPRP			; remember overprinting!
	TLNN (%TOSAI)			; FCS terminal?
	 JRST NOTSAI
	MOVEI X,1
	IORM X,MODSET			; set DM128 bit
	SETOM 128CHP
NOTSAI:	AND [%TOERS\%TOMVB\%TOMVU\%TOFCI\%TOLID\%TOCID\%TPCBS]
	CAMN [%TOERS\%TOMVB\%TOMVU\%TOFCI\%TOLID\%TOCID\%TPCBS]
	 JRST GREET
	MOVEI X,[ASCIZ/Insufficient terminal capabilities!
/]
	OUTSTR (X)
	PUSHJ P,SNDMSG
	JRST SUICID
SUBTTL Final initialization

; Greet the user

GREET:	MOVEI X,[ASCIZ/SU A.I. Lab KL-10
/]
	PUSHJ P,SNDMSG

; Get a PTY, put its number in A and other places

	PTYGET A
	 JRST [	MOVEI X,[ASCIZ/All network ports in use.
/]
		PUSHJ P,SNDMSG
		PUSHJ P,CLOSER
		JRST SUICID]
	HRRZM A,TTYLIN			; dumb interrupts
	MOVSI (A)
	IORM GAGOFF
	IORM SETVSZ
	IORM MODSET

; Initialize the user's display mode

	MOVEI %TDNOP
	PUSHJ P,NETOCH
	MOVEI %TDCLR
	PUSHJ P,NETOCH
	PUSHJ P,NETSND

; And get the terminal ready

	MOVSI B,(DMLIN\IMPBIT\FCS)
	PTSETL A			; set initial bits
	MOVE TCMXV
	CAILE VSZMAX
	 MOVEI VSZMAX
	MOVEM TCMXV
	HRRM SETVSZ
	MOVE [-NTYSTS,,TYSBLK]
	TTYSET				; turn GAG bit off
	MOVEI B,↑M
	PTWR1W A
	MOVNI 1,LOKTMO
	MOVEM 1,IDLTIM			; initialize lock timeout
	LOCK				; keep response good
	SETZM NODETP			; okay to detach jobs now
	JRST MAINL0

; Main program loop

MAINL:	IWAIT				; wait for an interrupt
MAINL0:	AOSG NTINTP			; net input?
	 JRST NTISER
	AOSG PTINTP			; PTY input?
	 JRST PTISER
	JRST MAINL			; back to sleep for us
SUBTTL Network input interrupt

NTISER:	PUSHJ P,NETICH			; get character from the network
	 JRST MAINL0			; network input buffer empty
	SKIPL IDLTIM
	 LOCK
	MOVNI 1,LOKTMO
	MOVEM 1,IDLTIM			; reset idle time
	SKIPE BKYBTS			; if have bucky bits
	 JRST PTYSN0			; forget all this cruft
	SKIPE EATERP			; getting terminal name?
	 JRST [	IDPB TERMBP		; save character
		JUMPN NTISER
		SETZM EATERP		; got it all
		JRST NTISER]
	AOSN PRESCP
	 JRST [	CAIN ↑\			; quoted?
		 JRST PTYSN0
		TRZN 100		; bucky bits?
		 JRST NTISER		; losing somehow
		LSH 7
		MOVEM BKYBTS
		JRST NTISER]
	AOSN SDCMDP
	 JRST [	CAIN 301		; logout?
		 SETOM NODETP
		CAIN 302		; get terminal name?
		 JRST [	SETOM EATERP
			MOVEI ":
			IDPB TERMBP
			MOVEI <" >
			IDPB TERMBP
			JRST NTISER]
		JRST NTISER]
	CAIN 300			; start of protocol command?
	 JRST [	SETOM SDCMDP
		JRST NTISER]
	CAIN ↑\				; protocol escape command?
	 JRST [	SETOM PRESCP
		JRST NTISER]
; Send character to the PTY

PTYSN0:	MOVE B,
	IOR B,BKYBTS			; add in bucky bits
	SETZM BKYBTS
	MOVE X,B
	TRZ X,%TXMTA\%TXCTL		; get character without CONTROL and META
	CAIN X,%TXTOP\"β		; beta?
	 JRST @FNYQOT
	CAIE X,%TXTOP\"≡		; equivalence?
	 CAIN X,%TXTOP\"∨		; or?
FNYQOT:	  JRST [PUSH P,B
		SETZ B,			; quote with escape
		PTWR1S A
		 JFCL
		POP P,B
		JRST PTYSN1]
	CAIN X,%TXTOP\"_		; underscore?
	 JRST [	MOVEI X,137
		DPB X,[000700,,B]
		JRST PTYSN1]
	CAIN X,"←			; backarrow?
	 JRST [	MOVEI X,030
		DPB X,[000700,,B]
		JRST PTYSN1]
	CAIN X,↑Z			; [CALL]?
	 JRST [	MOVEI X,↑C		; yes, convert to our [CALL]
		DPB X,[000700,,B]
		JRST PTYSN1]
	CAIN X,%TXTOP\"A		; [ESCAPE]?
	 JRST [	SETZ B,
		JRST PTYSND]
	CAIN X,%TXTOP\"B		; [BREAK]?
	 JRST [	PUSH P,["-]
		SETZ B,
		JRST PTYSN2]
	CAIN X,%TXTOP\"C		; [CLEAR]?
	 JRST [	MOVEI B,↑↑
		JRST PTYSND]
PTYSN1:	TRZ B,%TXTOP			; flush top now
	TRZN B,%TXMTA			; meta set?
	 JRST PTYSND
	PUSH P,B
	MOVEI B,200			; <EDIT>[NULL]
PTYSN2:	PTWR1S A			; send prefix meta command
	 JFCL				; will lose soon enough
	POP P,B
PTYSND:	PTWR1S A			; send character to PTY
	 JRST [	MOVEI %TDBEL		; bell
		PUSHJ 17,NETOCH
		PUSHJ 17,NETSND		; output it
		JRST NTISER]
	JRST NTISER			; try for more user characters
SUBTTL PTY input interrupt

PTISER:	PTRD1S A			; get a character from the PTY
	 JRST MAINL0			; PTY input buffer empty
	SKIPGE IDLTIM
	 LOCK
PTISR1:	MOVNI 1,LOKTMO
	MOVEM 1,IDLTIM			; reset idle time
	ANDI B,377			; flush funny 400 bit
	AOSN LFFLSP			; flush a line feed?
	 CAIE B,↑J
	  CAIA
	   JRST DMNOP
	AOSN QUOTEP			; quote frob?
	 JRST DMSND
	AOSN GETCXP			; set X position?
	 CAIG B,<" >			; yes, abort?
	  JRST CHKCYP
	XORI B,140
	CAMLE B,TCMXH			; beyond screen limit?
	 SETZ B,
	MOVEM B,HPOS
	SETOM GETCYP
	JRST DMNOP

CHKCYP:	AOSN GETCYP			; set Y position?
	 CAIG B,<" >			; yes, abort?
	  JRST CHKDMC
	XORI B,140
	CAMLE B,TCMXV			; beyond screen limit?
	 SETZ B,
	MOVEM B,VPOS
	JRST SETCPS			; finally set position

CHKDMC:	CAIG B,<" >			; DM command?
	 XCT DMCTAB(B)
DMSND:	CAIN B,013			; integral sign?
	 JRST [	MOVEI B,177
		JRST DMSND0]
	CAIN B,"_			; underscore?
	 JRST [	MOVEI B,137
		JRST DMSND0]
	SKIPN 128CHP
	 JRST DMSND0
	CAIN B,"↑			; uparrow?
	 JRST [	MOVEI B,013
		JRST DMSND0]
	CAIN B,"←			; backarrow?
	 JRST [	MOVEI B,030
		JRST DMSND0]
	CAIN B,177			; integral sign?
	 JRST [	MOVEI B,013
		JRST DMSND0]
DMSND0:	CAIL B,200			; a %TD code?
	 JRST NOTPCH
	SKIPN OVRPRP
	 JRST ISPCH
	PUSHJ P,GETSMD
	TDNN X,(Y)
	 JRST MRKNBL			; position already blank
	MOVEI %TDDLF			; delete character at this position
	PUSHJ P,NETOCH
MRKNBL:	IORM X,(Y)			; mark position as non-blank
ISPCH:	AOS HPOS			; no, account for character
NOTPCH:	MOVE B
	PUSHJ P,NETOCH
DMNOP:	PTRD1S A			; try for more while here
	 CAIA
	  JRST PTISR1			; more coming
	PUSHJ P,NETSND			; force buffer out
	JRST MAINL0			; scan the world again
; Datamedia conversion subroutines

SCLEAR:	MOVEI %TDCLR			; clear screen
	PUSHJ P,NETOCH
	SETZM HPOS			; home up
	SETZM VPOS
	SKIPN OVRPRP
	 JRST CANCEL
	SETZM SCRMST			; clear screen bit mask
	MOVE [SCRMST,,SCRMST+1]
	BLT SCRMST+3*VSZMAX-1
	CAIA				; roll isn't cancelled by this
CANCEL:	 SETZM ROLLP
	SETZM INDLMP
	MOVEI %TDRST
	PUSHJ P,NETOCH
	JRST DMNOP

CLEOL:	MOVEI %TDEOL
	PUSHJ P,NETOCH
	SKIPN OVRPRP
	 JRST DMNOP
	PUSHJ P,GETSMD
	ANDCAM X,(Y)			; flag current position as blank
	SUBI X,1
	ANDCAM X,(Y)			; flag rest of word as blank
	CAIE Z,2
	 SETZM 1(Y)			; 0 or 1 → flag next word as blank
	JUMPN Z,DMNOP
	SETZM 2(Y)			; 0 → flag word after that as blank
	JRST DMNOP

SETCPS:	MOVEI %TDMV0			; set cursor position
	PUSHJ P,NETOCH
	MOVE VPOS
	PUSHJ P,NETOCH
	MOVE HPOS
	PUSHJ P,NETOCH
	JRST DMNOP

INSLIN:	MOVEI %TDILP
	SKIPN OVRPRP
	 JRST IDCMND
	MOVEI X,VSZMAX-1
	SUB X,VPOS			; # of lines to move
	IMULI X,3
	ADDI X,377777			; # of lines-1 w/ sign bit
	HRL X,X
	HRRI X,SCRMST+3*<VSZMAX-1>-1	; source address
	POP X,3(X)			; reverse BLT
	JUMPL X,.-1
IDCMND:	PUSHJ P,NETOCH			; insert/delete mode command
	MOVEI 1
	PUSHJ P,NETOCH
	JRST DMNOP

SPACE:	MOVEI %TDDLF
	PUSHJ P,NETOCH
	SKIPN OVRPRP
	 JRST FORSPC
	PUSHJ P,GETSMD
	ANDCAM X,(Y)			; flag position as blank
FORSPC:	MOVEI %TDFS			; forespace
	PUSHJ P,NETOCH
	AOS HPOS
	JRST DMNOP
SUBTTL Datamedia command table

DMCTAB:	JRST DMNOP			; ↑@ no-op
	JRST DMNOP			; ↑A no-op
	JRST [	SETZM HPOS		; ↑B home up
		SETZM VPOS
		JRST SETCPS]
	JRST DMNOP			; ↑C no-op
	JRST DMNOP			; ↑D no-op
	JRST DMNOP			; ↑E no-op
	JRST DMNOP			; ↑F no-op
	MOVEI B,%TDBEL			; ↑G bell
	JRST [	SKIPE INDLMP		; ↑H backspace/delete character
		 JRST [	MOVEI %TDDCP
			SKIPN OVRPRP
			 JRST IDCMND
			PUSHJ P,GETSMD
			MOVE B,(Y)
			LSH X,1
			SUBI X,1	; mask for bits being hacked
			ANDCAM X,(Y)
			LSH B,1		; shift characters over
			AND B,X
			IORM B,(Y)
			CAIN Z,2
			 JRST IDCMND
			MOVEI C,1	; bit to bring in previous words if needed
			MOVE B,1(Y)
			LSH B,1		; shift characters over
			TLZE B,(1←32.)
			 IORM C,(Y)	; bring in overflow to next word
			MOVEM B,1(Y)
			JUMPN Z,IDCMND	; if last word flush
			MOVE B,2(Y)
			LSH B,1
			TLZE B,(1←32.)
			 IORM C,1(Y)
			MOVEM B,2(Y)
			JRST IDCMND]
		SOSGE HPOS
		 SETZM HPOS
		JRST SETCPS]
	JRST [	MOVE HPOS		; ↑I tab
		TRZ 7
		ADDI 8.
		MOVEM HPOS
		JRST SETCPS]
	JRST [	SKIPE INDLMP		; ↑J line feed/insert line
		 JRST INSLIN
		AOS VPOS
		JRST SETCPS]
	JRST DMNOP			; ↑K tab clear (no-op)
	JRST [	SETOM GETCXP		; ↑L cursor position
		JRST DMNOP]
	JRST [	AOS X,VPOS		; ↑M terpri
		SETZM HPOS
		SETOM LFFLSP
		SKIPN ROLLP		; scrolling?
		 JRST [	CAML X,TCMXV	; not scrolling; gone off bottom?
			 SETZM VPOS	; yes, wrap around to top of screen
			JRST SETCPS]	; use %TDMV0 to move cursor
		MOVEI %TDCRL		; scrolling, use %TDCRL instead
		PUSHJ P,NETOCH
		CAMGE X,TCMXV
		 JRST DMNOP
		MOVE TCMXV		; somehow we scrolled
		SOS
		MOVEM VPOS
		MOVE [SCRMST+3,,SCRMST]
		BLT SCRMST+3*VSZMAX-1
		JRST DMNOP]
	MOVEI B,%TDBOW			; ↑N blink on (set complement mode)
	JRST DMNOP			; ↑O bold on (no-op)
	JRST [	SETOM INDLMP		; ↑P enter I/D mode
		JRST DMNOP]
; More DM command frobs

	JRST DMNOP			; ↑Q transmit page to computer (no-op)
	JRST DMNOP			; ↑R transmit page to printer (no-op)
	JRST DMNOP			; ↑S transmit line to computer (no-op)
	JRST DMNOP			; ↑T no-op
	JRST DMNOP			; ↑U no-op
	JRST DMNOP			; ↑V no-op
	JRST CLEOL			; ↑W erase to end of line
	JRST CANCEL			; ↑X cancel bold, I/D, roll
	JRST DMNOP			; ↑Y set tab (no-op)
	JRST [	SKIPE INDLMP		; ↑Z line starve/delete row
		 JRST [	MOVEI %TDDLP
			SKIPN OVRPRP
			 JRST IDCMND
			MOVE X,VPOS
			LSH X,1
			ADD X,VPOS
			ADDI X,SCRMST
			HRLI X,3(X)
			BLT X,SCRMST+3*VSZMAX-1
			JRST IDCMND]
		SOSGE VPOS
		 SETZM VPOS
		JRST SETCPS]
	JRST [	SETOM QUOTEP		; ↑[ quote FCS character
		JRST DMNOP]
	JRST [	SKIPN INDLMP		; ↑\ forespace/insert character
		 JRST FORSPC
		MOVEI %TDICP
		SKIPN OVRPRP
		 JRST IDCMND
		PUSHJ P,GETSMD
		MOVE B,(Y)
		LSH X,1
		SUBI X,1		; fill in mask to the right
		ANDCAM X,(Y)
		AND B,X
		LSHC B,-1
		IORM B,(Y)
		CAIN Z,2
		 JRST IDCMND
		MOVE B,1(Y)
		SKIPGE C
		 TLO B,(1←31.)		; bring in bit from previous word
		LSHC B,-1
		MOVEM B,1(Y)
		JUMPN Z,IDCMND
		MOVE B,2(Y)
		SKIPGE C
		 TLO B,(1←31.)
		LSH B,-1
		TRZ B,100000		; flush overflow bit
		MOVEM B,2(Y)
		JRST IDCMND]
	JRST [	SETOM ROLLP		; ↑] roll on
		JRST DMNOP]
	JRST SCLEAR			; ↑↑ master clear
	JRST SCLEAR			; ↑← erase screen
	JRST SPACE			; sp delete character and forespace
IFN .-DMCTAB-1-" ,.ERR DMCTAB loses!
SUBTTL Subroutines

; Get screen mask data in Y, Z, X

GETSMD:	MOVE Y,VPOS
	LSH Y,1
	ADD Y,VPOS
	MOVE Z,HPOS
	LSH Z,-5			; Z ← word index in line (for cleol)
	ADDI Y,SCRMST(Z)		; Y ← addr of screen mask word
	MOVE X,HPOS
	ANDI X,37
	MOVE X,BITTAB(X)		; X ← mask for this byte
	POPJ P,

; Bit table

BITTAB:	REPEAT 32.,1←<31.-.RPCNT>	; bit table

; Send a message, b.p. in X

SNDMSG:	TLOA X,440700			; set up b.p.
MSGLUP:	 PUSHJ P,NETOCH
	ILDB X
	JUMPN MSGLUP			; continue until a null hit
	JRST NETSND

; Here to suicide on network errors or idle timeout

INTDIE:	INTMSK [0]			; no more interrupts
	DEBREAK				; out of interrupt level
SUICID:	OUTSTR [ASCIZ/Connection closed.
/]
	SKIPE NODETP
	 JRST DIEDIE			; logout the guy
	MOVE A,TTYLIN
	TTYJOB A,
	JUMPE A,DIEDIE
	MOVE A,TTYLIN
	MOVEI B,7
	PTJOBX A			; clear PTY's input buffer
	PTRD1S A			; slurp up stuff in buffer
	 CAIA
	  JRST .-2
	MOVEI B,[.BYTE 9 ? 600 ? 600 ? "D ? "E ? "T ? "A ? "C ? "H ? ↑M ? ↑J ? 0]
	PTWRS9 A
	MOVEI 5.
	SLEEP				; give it time to happen
	PTRD1S A			; slurp up what's left in the buffer
	 JRST DIEDIE
	JRST .-2
DIEDIE:	RESET ? EXIT

...LIT:	CONSTANTS

; Wonderful network routines

SVRRTS==-1				; include server routines
ERRTNS==-1				; include error routines
ERRHAN==-1				; include automagic error handling
ERRINS==<JRST SUICID>			; error instruction
HSTTAB==-1				; include host table magic
HSTSIX==-1				; and alias name kludge

.INSRT NETWRK[NET,MRC]

END SUPSER